package core

import (
	"chatgpt/utils"
	"encoding/json"
	"fmt"
	"reflect"
	"sort"
	"strings"
)

// GPT
type GPT struct {
	ApiKey  string
	Proxy   string
	Timeout int
}

// messages
var messages []Message

// Message
// 单个消息
type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

// Payload
// 请求数据
type Payload struct {
	Model    string    `json:"model"`
	Messages []Message `json:"messages"`
}

// AnswerItem
// 回答数据
type AnswerItem struct {
	FinishReason string  `json:"finish_reason"`
	Index        int     `json:"index"`
	Message      Message `json:"message"`
}

// Answer
// 回答
type Answer struct {
	Id      string       `json:"id"`
	Object  int          `json:"object"`
	Created interface{}  `json:"created"`
	Model   string       `json:"model"`
	Usage   interface{}  `json:"usage"`
	Choices []AnswerItem `json:"choices"`
}

// BuildApiPayload
// 构建Api数据
//
//	@param question
//	@return string
func BuildApiPayload(question string) string {
	messages = append(messages, Message{
		Role:    "user",
		Content: question,
	})

	payload := Payload{
		Model:    "gpt-3.5-turbo",
		Messages: messages,
	}

	str, _ := json.Marshal(&payload)
	return string(str)
}

// Request
// 请求体
type Request struct {
	Words string `json:"words"`
	Time  int    `json:"time"`
	Sign  string `json:"sign"`
}

// Response
// 响应体
type Response struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data string `json:"data"`
	Sign string `json:"sign"`
}

// ResponseData
// 响应数据
type ResponseData map[string]interface{}

// BuildResponse
// 构建响应体
//
//	@param privateKey
//	@param code
//	@param msg
//	@param data
//	@return string
func BuildResponse(privateKey string, code int, msg string, data ResponseData) string {
	resp := Response{
		Code: code,
		Msg:  msg,
	}
	dataJson, _ := json.Marshal(data)
	resp.Data = utils.Base64{
		Content: []byte(dataJson),
	}.Encode()
	if privateKey != "" {
		resp.Sign = MakeSign(resp, privateKey)
	}

	respJson, _ := json.Marshal(resp)

	return string(respJson)
}

// MakeSign
// 生成签名
//
//	@param obj
//	@param privateKey
//	@return string
func MakeSign(obj interface{}, privateKey string) string {
	valueOfObj := reflect.ValueOf(obj)
	keysCount := valueOfObj.NumField()

	keys := make([]string, keysCount)
	for i := 0; i < keysCount; i++ {
		keys[i] = valueOfObj.Type().Field(i).Name
	}
	sort.Strings(keys)

	str := ""
	currentKey := ""
	var currentValue reflect.Value
	for j := 0; j < keysCount; j++ {
		currentKey = strings.ToLower(keys[j])
		if currentKey == "sign" {
			continue
		}
		currentValue = valueOfObj.FieldByName(keys[j])
		str = fmt.Sprintf("%s%s=%v&", str, currentKey, currentValue)
	}

	return utils.Md5(str + "key=" + privateKey)
}
